
#include <stdio.h>
#include <string.h>
#include <Windows.h>
#include "Math.h"
#include "matrix.h"
#include "scene_parser.h"
#include "KDTree.h"


SceneParser::SceneParser() 
{
	initialize();
}

SceneParser::SceneParser(const char* filename)
{
	initialize();

	// open the file
	assert(filename != NULL);
	const char *ext = &filename[strlen(filename)-4];
	assert(!strcmp(ext,".txt"));
	m_file = fopen(filename,"r");
	assert (m_file != NULL);

	// parse the scene
	parseFile();

	// close the file
	fclose(m_file); 
	m_file= NULL;
}

SceneParser::~SceneParser() 
{
	if (m_pSceneTree != NULL) 
		delete m_pSceneTree;
	if (m_pCamera != NULL) 
		delete m_pCamera;
	for (size_t i=0; i < m_vpMaterials.size(); i++)
		delete ((Material*)m_vpMaterials[i]);
	for (size_t i=0; i < m_vpLights.size(); i++)
		delete ((Light*)m_vpLights[i]);
}

void SceneParser::initialize() 
{
	m_pCamera = NULL;
	m_background_color = Vec3f(0.5,0.5,0.5);
	m_ambient_light = Vec3f(0.f,0.f,0.f);
	m_pSceneTree = NULL;
	m_file = NULL;
	m_pCurrent_material = NULL;
}

// ====================================================================
// ====================================================================

void SceneParser::parseFile() 
{
	float startTime = timeGetTime();
	printf("\nstep 1: File parsing... ");
	char token[MAX_PARSER_TOKEN_LENGTH];
	while (getToken(token)) { 
		if (!strcmp(token, "RenderConfig")) {
			parseRenderConfig();
		} else if (!strcmp(token, "OrthographicCamera")) {
			parseOrthographicCamera();
		} else if (!strcmp(token, "PerspectiveCamera")) {
			parsePerspectiveCamera();
		} else if (!strcmp(token, "Lights")) {
			parseLights();
		} else if (!strcmp(token, "Background")) {
			parseBackground();
		} else if (!strcmp(token, "Materials")) {
			parseMaterials();
		} else if (!strcmp(token, "Group")) {
			if ( m_pSceneTree )
				delete m_pSceneTree;
			if ( !strcmp( m_config.sceneTree, "kd-tree" ) )
				m_pSceneTree = new KDTree();
			else
				m_pSceneTree = new KDTree();
			parseGroup();
			printf("%.3fs face_amount=%d\n",(timeGetTime()-startTime)/1000.f,
				m_pSceneTree->getFaceAmout());
			m_pSceneTree->buildTree();
		} else {
			printf ("Unknown token in parseFile: '%s'\n", token);
			exit(0);
		}
	}
}

void SceneParser::parseRenderConfig()
{
	char token[MAX_PARSER_TOKEN_LENGTH];
	// read in the sphere parameters
	getToken(token); assert (!strcmp(token, "{"));
	while ( getToken(token) )
	{
		/*sample 1 
			size 400 400 
			output output\rabbit_1.tga 
			bounces 2 
			weight 0.5
			*/
		if ( !strcmp(token, "size") ) {
			m_config.width = readInt();
			m_config.height = readInt();
		}
		else if ( !strcmp(token, "sample") )
			m_config.sample = readInt();
		else if ( !strcmp(token, "output") )
			readString( m_config.output );
		else if ( !strcmp(token, "bounces") )
			m_config.max_bounces = readInt();
		else if ( !strcmp(token, "weight") )
			m_config.minWeight = readFloat();
		else if ( !strcmp(token, "tree") )
			readString( m_config.sceneTree );
		else if( !strcmp(token, "}") )
			break;
		else {
			printf ("Unknown token in parseRenderConfig: '%s'\n", token);
			exit(0);
		}
	}
}

void SceneParser::parseOrthographicCamera() 
{
	char token[MAX_PARSER_TOKEN_LENGTH];
	// read in the camera parameters
	getToken(token); assert (!strcmp(token, "{"));
	getToken(token); assert (!strcmp(token, "center"));
	Vec3f center = readVec3f();
	getToken(token); assert (!strcmp(token, "direction"));
	Vec3f direction = readVec3f();
	getToken(token); assert (!strcmp(token, "up"));
	Vec3f up = readVec3f();
	getToken(token); assert (!strcmp(token, "size"));
	float size = readFloat();
	getToken(token); assert (!strcmp(token, "}"));
	m_pCamera = new OrthographicCamera(center,direction,up,size);
}

void SceneParser::parsePerspectiveCamera() 
{
	char token[MAX_PARSER_TOKEN_LENGTH];
	// read in the camera parameters
	getToken(token); assert (!strcmp(token, "{"));
	getToken(token); assert (!strcmp(token, "center"));
	Vec3f center = readVec3f();
	getToken(token); assert (!strcmp(token, "direction"));
	Vec3f direction = readVec3f();
	getToken(token); assert (!strcmp(token, "up"));
	Vec3f up = readVec3f();
	getToken(token); assert (!strcmp(token, "angle"));
	float angle_degrees = readFloat();
	float angle_radians = DegreesToRadians(angle_degrees);
	getToken(token); assert (!strcmp(token, "HSW"));
	float hsw = readFloat();
	getToken(token); assert (!strcmp(token, "}"));
	m_pCamera = new PerspectiveCamera(center,direction,up,angle_radians,hsw);
}

void SceneParser::parseLights() 
{
	char token[MAX_PARSER_TOKEN_LENGTH];
	getToken(token); assert (!strcmp(token, "{"));

	// read in the objects
	while ( getToken(token) ) {
		if (!strcmp(token, "DirectionalLight")) {
			getToken(token); assert (!strcmp(token, "{"));
			getToken(token); assert (!strcmp(token, "direction"));
			Vec3f direction = readVec3f();
			getToken(token); assert (!strcmp(token, "color"));
			Vec3f color = readVec3f();
			getToken(token); assert (!strcmp(token, "}"));
			m_vpLights.push_back(new DirectionalLight(direction,color));
		} else if (!strcmp(token, "PointLight")) {
			getToken(token); assert (!strcmp(token, "{"));
			getToken(token); assert (!strcmp(token, "position"));
			Vec3f position = readVec3f();
			getToken(token); assert (!strcmp(token, "color"));
			Vec3f color = readVec3f();
			float attenuation_1 = 1; float attenuation_2 = 0; float attenuation_3 = 0;
			getToken(token); assert (!strcmp(token, "attenuation"));
			attenuation_1 = readFloat(); attenuation_2 = readFloat(); attenuation_3 = readFloat();
			getToken(token); assert (!strcmp(token, "}"));
			m_vpLights.push_back(new PointLight(position,color,attenuation_1,attenuation_2,attenuation_3));
		} else if (!strcmp(token, "AreaLight")) {
			getToken(token); assert (!strcmp(token, "{"));
			getToken(token); assert (!strcmp(token, "length"));
			float length = readFloat();
			getToken(token); assert (!strcmp(token, "number"));
			int number = readInt();
			getToken(token); assert (!strcmp(token, "position"));
			Vec3f position = readVec3f();
			getToken(token); assert (!strcmp(token, "color"));
			Vec3f color = readVec3f();
			float attenuation_1 = 1; float attenuation_2 = 0; float attenuation_3 = 0;
			getToken(token); assert (!strcmp(token, "attenuation"));
			attenuation_1 = readFloat(); attenuation_2 = readFloat(); attenuation_3 = readFloat();
			getToken(token); assert (!strcmp(token, "}"));
			Vec3f eachColor = color * (1.f/(number*number));
			Vec3f eachPosition; eachPosition[1] = position[1];
			int center = number/2;
			for (int i=0; i < number; i++)
			for (int j=0; j < number; j++)
			{
				float x = (float)(j-center)/number; float z = (float)(i-center)/number;
				eachPosition[0] = x * length + position[0];
				eachPosition[2] = z * length + position[2];
				m_vpLights.push_back(new PointLight(eachPosition,eachColor,attenuation_1,attenuation_2,
					attenuation_3));
			}
		} else if (!strcmp(token, "}")) {
			break;
		} else {
			printf ("Unknown token in parseGroup: '%s'\n", token);
			exit(0);
		}   
	}
}

void SceneParser::parseBackground() 
{
	char token[MAX_PARSER_TOKEN_LENGTH];
	// read in the background color
	getToken(token); assert (!strcmp(token, "{"));  
	while (1) {
		getToken(token); 
		if (!strcmp(token, "}")) { 
			break;  
		} else if (!strcmp(token, "color")) {
			m_background_color = readVec3f();
		} else if (!strcmp(token, "ambientLight")) {
			m_ambient_light = readVec3f();
		} else {
			printf ("Unknown token in parseBackground: '%s'\n", token);
			assert(0);
		}
	}
}

void SceneParser::parseMaterials() 
{
	char token[MAX_PARSER_TOKEN_LENGTH];
	getToken(token); assert (!strcmp(token, "{"));

	// read in the objects
	while ( getToken(token) ) 
	{ 
		if ( !strcmp(token, "PhongMaterial") ) 
		{
			getToken(token); assert (!strcmp(token, "{"));
			Vec3f ambientColor(0.f,0.f,0.f);
			Vec3f diffuseColor(0,0,0);
			Vec3f specularColor(0,0,0);
			float exponent = 1;
			Vec3f transparentColor(0,0,0);
			Vec3f reflectiveColor(0,0,0);
			float indexOfRefraction = 1;
			char diffuseMap[100];
			bool hasTexture = false;
			while (1) 
			{
				getToken(token); 
				if (!strcmp(token, "ambientColor")) {
					ambientColor = readVec3f();
				} else if (!strcmp(token, "diffuseColor")) {
					diffuseColor = readVec3f();
				} else if (!strcmp(token, "specularColor")) {
					specularColor = readVec3f();
				} else if  (!strcmp(token, "exponent")) {
					exponent = readFloat();
				} else if (!strcmp(token, "transparentColor")) {
					transparentColor = readVec3f();
				} else if (!strcmp(token, "reflectiveColor")) {
					reflectiveColor = readVec3f();
				} else if (!strcmp(token, "indexOfRefraction")) {
					indexOfRefraction = readFloat();
				} else if (!strcmp(token, "diffuseMAP")) {
					readString( diffuseMap );
					hasTexture = true;
				} else {
					assert (!strcmp(token, "}"));
					break;
				}
			}
			// CALLING ASSIGNMENT 3 CODE
			if ( hasTexture )
				m_vpMaterials.push_back( new TextureMaterial(
					ambientColor,diffuseColor,specularColor,exponent,
					transparentColor,reflectiveColor,indexOfRefraction, 
					diffuseMap) );
			else
				m_vpMaterials.push_back(new PhongMaterial(
					ambientColor,diffuseColor,specularColor,exponent,
					transparentColor,reflectiveColor,indexOfRefraction));
		}
		else if ( !strcmp(token, "}") )
			break;
	}
}  

void SceneParser::parseGroup() 
{
	char token[MAX_PARSER_TOKEN_LENGTH];
	getToken(token); assert (!strcmp(token, "{"));

	// read in the objects
	while ( getToken(token) )
	{
		if ( !strcmp(token, "MaterialIndex") ) {
			int index = readInt();
			assert (index >= 0 && index <= getNumMaterials());
			m_pCurrent_material = getMaterial(index);
		} else if( !strcmp(token, "Transform") ) {
			// everything else does count
			parseTransform();
		} else if ( !strcmp(token, "}") )
			break;
	}
}

void SceneParser::parseTransform() 
{
	char token[MAX_PARSER_TOKEN_LENGTH];
	Matrix *pMatrix = new Matrix(); 
	pMatrix->SetToIdentity();
	getToken(token); assert (!strcmp(token, "{"));

	getToken(token);
	while (1) {
		if (!strcmp(token,"Scale")) {
			getToken(token); assert (!strcmp(token, "{"));
			*pMatrix *= Matrix::MakeScale(readVec3f());
			getToken(token); assert (!strcmp(token, "}"));
		} else if (!strcmp(token,"XRotate")) {
			getToken(token); assert (!strcmp(token, "{"));
			*pMatrix *= Matrix::MakeXRotation(DegreesToRadians(readFloat()));
			getToken(token); assert (!strcmp(token, "}"));
		} else if (!strcmp(token,"YRotate")) {
			getToken(token); assert (!strcmp(token, "{"));
			*pMatrix *= Matrix::MakeYRotation(DegreesToRadians(readFloat()));
			getToken(token); assert (!strcmp(token, "}"));
		} else if (!strcmp(token,"ZRotate")) {
			getToken(token); assert (!strcmp(token, "{"));
			*pMatrix *= Matrix::MakeZRotation(DegreesToRadians(readFloat()));
			getToken(token); assert (!strcmp(token, "}"));
		} else if (!strcmp(token,"Rotate")) {
			getToken(token); assert (!strcmp(token, "{"));
			Vec3f axis = readVec3f();
			float degrees = readFloat();
			*pMatrix *= Matrix::MakeAxisRotation(axis,DegreesToRadians(degrees));
			getToken(token); assert (!strcmp(token, "}"));
		} else if (!strcmp(token,"Translate")) {
			getToken(token); assert (!strcmp(token, "{"));
			*pMatrix *= Matrix::MakeTranslation(readVec3f());
			getToken(token); assert (!strcmp(token, "}"));
		} else if (!strcmp(token,"Matrix")) {
			Matrix matrix2; matrix2.SetToIdentity();
			getToken(token); assert (!strcmp(token, "{"));
			for (int j = 0; j < 4; j++) {
				for (int i = 0; i < 4; i++) {
					float v = readFloat();
					matrix2.Set(i,j,v); } }
			getToken(token); assert (!strcmp(token, "}"));
			*pMatrix = matrix2 * (*pMatrix);
		} else if (!strcmp(token, "TriangleMesh")){
			parseTriangleMesh(pMatrix);
			break;
		} else if (!strcmp(token, "TextureTriangleMesh")){
			parseTextureMesh(pMatrix);
			break;
		} else if (!strcmp(token, "Triangle")){
			parseTriangle(pMatrix);
			break;
		} else if (!strcmp(token, "Sphere")){
			parseSphere();
			break;
		}
		else
			break;
		getToken(token);
	}
	getToken(token); assert (!strcmp(token, "}"));
}

void SceneParser::parseTriangleMesh(Matrix *pMatrix) 
{
	char token[MAX_PARSER_TOKEN_LENGTH];
	char filename[MAX_PARSER_TOKEN_LENGTH];

	// get the filename
	getToken(token); assert (!strcmp(token, "{"));
	getToken(token); assert (!strcmp(token, "obj_file"));
	getToken(filename); 
	getToken(token); assert (!strcmp(token, "}"));
	const char *ext = &filename[strlen(filename)-4];
	assert(!strcmp(ext,".obj"));

	// make arrays
	std::vector<Vec3f> vv;

	// read it again, save it
	FILE *pFile = fopen(filename,"r");
	char path[100];
	if (!pFile)
	{
		sprintf(path, "scenes/%s", filename);
		pFile = fopen(path, "r");
	}
	assert (pFile != NULL);
	while (1) {
		int c = fgetc(pFile);
		if (c == EOF) { 
			break;
		} else if (c == 'v') { 
			float v0,v1,v2;
			fscanf (pFile,"%f %f %f",&v0,&v1,&v2);
			vv.push_back(Vec3f(v0,v1,v2));
		} else if (c == 'f') {
			int f0,f1,f2;
			fscanf (pFile,"%d %d %d",&f0,&f1,&f2);
			// indexed starting at 1...
			assert (f0 > 0 && f0 <= vv.size());
			assert (f1 > 0 && f1 <= vv.size());
			assert (f2 > 0 && f2 <= vv.size());
			Vec3f v0 = vv[f0-1]; pMatrix->Transform(v0);
			Vec3f v1 = vv[f1-1]; pMatrix->Transform(v1);
			Vec3f v2 = vv[f2-1]; pMatrix->Transform(v2);
			Triangle *pTriangle = new Triangle(v0,v1,v2,m_pCurrent_material);
			m_pSceneTree->addTriangle(pTriangle);
		} // otherwise, must be whitespace
	}
	fclose(pFile);
}


void getTokenBy(FILE *pFile,char endC,char token[])
{
	char c; int suc;
	for (int i=0;;i++){
		suc = fscanf(pFile, "%c", &c);
		while ( i==0 && c==' '){
			suc = fscanf(pFile, "%c", &c);
		}
		if ( c!=endC &&  (c!=' ') && c!= '\n') token[i]=c;
		else {token[i] = '\0';break;}
	}
}

void SceneParser::parseTextureMesh(Matrix *pMatrix)
{
	char token[MAX_PARSER_TOKEN_LENGTH];
	char filename[MAX_PARSER_TOKEN_LENGTH];

	// get the filename
	getToken(token); assert (!strcmp(token, "{"));
	getToken(token); assert (!strcmp(token, "obj_file"));
	getToken(filename); 
	getToken(token); assert (!strcmp(token, "}"));
	const char *ext = &filename[strlen(filename)-4];
	assert(!strcmp(ext,".obj"));

	// make arrays
	std::vector<char *> vname;
	std::vector<Material *> vmatrial;
	std::vector<Vec3f> vv;
	std::vector<Vec2f> vt;
	std::vector<Vec3f> vn;
	int state = 0; //1=v\vt\vn 2=face

	FILE *pFile = fopen(filename,"r");
	if ( !pFile )
	{
		char path[100];
		sprintf(path, "scenes/%s", filename);
		pFile = fopen(path, "r");
	}
	assert (pFile != NULL);
	Vec3f tempV3; Vec2f tempV2;
	while (getToken(token,pFile)) {
		if (state == 0){
			if (!strcmp(token,"mtllib")){
				// insky
				getToken(token,pFile);
				FILE *pMatrialFile = fopen(token,"r");
				if ( !pMatrialFile )
				{
					char path[100];
					sprintf(path, "scenes/%s", token);
					pMatrialFile = fopen(path, "r");
				}
				assert(pMatrialFile);
				int t = getToken(token,pMatrialFile);
				while(t){
					if (!strcmp(token,"newmtl")){
						t = getToken(token,pMatrialFile);
						char *str = new char[30];
						strcpy(str,token);
						vname.push_back(str);
						Vec3f ambientColor(0.f,0.f,0.f);
						Vec3f diffuseColor(1,1,1);
						Vec3f specularColor(0,0,0);
						float exponent = 1;
						Vec3f transparentColor(0,0,0);
						Vec3f reflectiveColor(0,0,0);
						float indexOfRefraction = 1;
						char textureFileName[MAX_PARSER_TOKEN_LENGTH];
						bool hasTexture = false;
						while (1) {
							t = getToken(token,pMatrialFile);
							if (!t) break;
							if (!strcmp(token, "Ka")) {
								ambientColor = readVec3f(pMatrialFile);
							} else if (!strcmp(token, "Kd")) {
								diffuseColor = readVec3f(pMatrialFile);
							} else if (!strcmp(token, "Ks")) {
								specularColor = readVec3f(pMatrialFile);
							} else if  (!strcmp(token, "Ns")) {
								exponent = readFloat(pMatrialFile);
							} else if (!strcmp(token, "d")) {
								float d = 1.0f - readFloat(pMatrialFile);
								transparentColor.Set(d,d,d);
							} else if (!strcmp(token,"s")){
								float s = readFloat(pMatrialFile);
								reflectiveColor.Set(s,s,s);
							} else if (!strcmp(token,"map_Ka") || !strcmp(token,"map_Kd")){
								hasTexture = true;
								getToken(textureFileName,pMatrialFile);
							} else {
								break;
							}
						}
						// CALLING ASSIGNMENT 3 CODE
						Material *pMaterial = NULL;
						if (hasTexture){
							pMaterial = new TextureMaterial(ambientColor,diffuseColor,specularColor,
								exponent,transparentColor,reflectiveColor,indexOfRefraction,textureFileName);
						} else {
							pMaterial = new PhongMaterial(ambientColor,diffuseColor,specularColor,
								exponent,transparentColor,reflectiveColor,indexOfRefraction);
						}
						vmatrial.push_back(pMaterial);
						m_vpMaterials.push_back(pMaterial);
					} else {
						t = getToken(token,pMatrialFile);
					}
				}
				fclose(pMatrialFile);
			} else if (!strcmp(token,"g")){
			} else if (!strcmp(token,"v")){
				state = 1;
				tempV3 = readVec3f(pFile); vv.push_back(tempV3);
			} else {
#ifdef __debug__
printf("word %s error:%d;",token,state);
#endif
			}
		} else if (state == 1){
			if (!strcmp(token,"v")){
				tempV3 = readVec3f(pFile); vv.push_back(tempV3);
			} else if (!strcmp(token,"vn")){
				tempV3 = readVec3f(pFile); vn.push_back(tempV3);
			} else if (!strcmp(token,"vt")){
				tempV2 = readVec2f(pFile); vt.push_back(tempV2);
			} else if (!strcmp(token,"g")){
				state = 2;
			} else if (!strcmp(token,"usemtl")){
				state = 2; 
				goto usemtl;
			} else if(!strcmp(token,"f")){
				state = 2;
				goto face;
			} else {
#ifdef __debug__
printf("word %s error:%d;",token,state);
#endif
			}
		} else if (state == 2){
			if (!strcmp(token,"f")){
face:			//f 970//970 584//584 909//909
				int v[3],n[3],t[3];
				for(int i=0;i<3;i++){
					getTokenBy(pFile,'/',token);
					if (token[0]!='\0') sscanf(token,"%d",&v[i]);
					else assert(0);
					getTokenBy(pFile,'/',token);
					if (token[0]!='\0') sscanf(token,"%d",&t[i]);
					else t[i]=-1;
					getTokenBy(pFile,'/',token);
					if (token[0]!='\0') sscanf(token,"%d",&n[i]);
					else n[i]=-1;
				}
				Vec3f vv0 = vv[v[0]-1]; pMatrix->Transform(vv0);
				Vec3f vv1 = vv[v[1]-1]; pMatrix->Transform(vv1);
				Vec3f vv2 = vv[v[2]-1]; pMatrix->Transform(vv2);
				if (t[0]==-1 || !m_pCurrent_material->hasTexture()){
					if (n[0]==-1){
						Triangle *pTriangle =  new Triangle(vv0,vv1,vv2,m_pCurrent_material);
						m_pSceneTree->addTriangle(pTriangle);
					} else {
						Vec3f vn0 = vn[n[0]-1]; pMatrix->TransformDirection(vn0); vn0.Normalize();
						Vec3f vn1 = vn[n[1]-1]; pMatrix->TransformDirection(vn1); vn1.Normalize();
						Vec3f vn2 = vn[n[2]-1]; pMatrix->TransformDirection(vn2); vn2.Normalize();
						NormalTriangle *pTriangle = new NormalTriangle(vv0,vv1,vv2,vn0,vn1,vn2,m_pCurrent_material);
						m_pSceneTree->addTriangle(pTriangle);
					}
				} else {
					Vec3f vn0,vn1,vn2;
					if (n[0]!=-1){
						vn0 = vn[n[0]-1]; pMatrix->TransformDirection(vn0); vn0.Normalize();
						vn1 = vn[n[1]-1]; pMatrix->TransformDirection(vn1); vn1.Normalize();
						vn2 = vn[n[2]-1]; pMatrix->TransformDirection(vn2); vn2.Normalize();
					}
					Vec2f vt0 = vt[t[0]-1]; Vec2f vt1 = vt[t[1]-1]; Vec2f vt2 = vt[t[2]-1];
					TextureTriangle *pTriangle = new TextureTriangle(vv0,vv1,vv2,
						vt0,vt1,vt2,vn0,vn1,vn2,m_pCurrent_material);
					m_pSceneTree->addTriangle(pTriangle);
				}
			} else if (!strcmp(token,"s")){
				readInt(pFile);
			} else if (!strcmp(token,"usemtl")){
usemtl:			// matrial 
				getToken(token,pFile);
				for (size_t i=0; i < vname.size(); i++)
					if (!strcmp(token,vname[i])){
						m_pCurrent_material = vmatrial[i];
						break;
					}
			} else if (!strcmp(token,"g")){
				state = 1;
			} else if (!strcmp(token,"v")){
				state = 1;
				tempV3 = readVec3f(pFile); vv.push_back(tempV3);
			} else {
#ifdef __debug__
printf("word %s error:%d;",token,state);
#endif
			}
		}
	}
	for (size_t i=0; i < vname.size(); i++)
		delete vname[i];
	fclose(pFile);
}
// 	char token[MAX_PARSER_TOKEN_LENGTH];
// 	char filename[MAX_PARSER_TOKEN_LENGTH];
// 
// 	// get the filename
// 	getToken(token); assert (!strcmp(token, "{"));
// 	getToken(token); assert (!strcmp(token, "obj_file"));
// 	getToken(filename); 
// 	getToken(token); assert (!strcmp(token, "}"));
// 	const char *ext = &filename[strlen(filename)-4];
// 	assert(!strcmp(ext,".obj"));
// 
// 	// make arrays
// 	std::vector<Vec3f> vv;
// 	std::vector<Vec2f> vt;
// 	std::vector<Vec3f> vn;
// 
// 	// read it again, save it
// 	FILE *pFile = fopen(filename,"r");
// 	assert (pFile != NULL);
// 	while (fscanf(pFile,"%s",token)!=EOF) {
// 		if (!strcmp(token,"v")) { 
// 			float v0,v1,v2;
// 			fscanf (pFile,"%f %f %f",&v0,&v1,&v2);
// 			vv.push_back(Vec3f(v0,v1,v2));
// 		} else if (!strcmp(token,"vn")) { 
// 				float v0,v1,v2;
// 				fscanf (pFile,"%f %f %f",&v0,&v1,&v2);
// 				vn.push_back(Vec3f(v0,v1,v2));
// 		} else if (!strcmp(token,"vt")){
// 			float v0,v1;
// 			fscanf (pFile,"%f %f",&v0,&v1);
// 			vt.push_back(Vec2f(v0,v1));
// 		} else if (!strcmp(token,"f")) {
// 			int v0,v1,v2,t0,t1,t2,n0,n1,n2;
// 			fscanf (pFile,"%d/%d/%d %d/%d/%d %d/%d/%d",&v0,&t0,&n0,&v1,&t1,&n1,&v2,&t2,&n2);
// 			// indexed starting at 1...
// 			assert (v0 > 0 && v0 <= vv.size());
// 			assert (v1 > 0 && v1 <= vv.size());
// 			assert (v2 > 0 && v2 <= vv.size());
// 			Vec3f vv0 = vv[v0-1]; pMatrix->Transform(vv0);
// 			Vec3f vv1 = vv[v1-1]; pMatrix->Transform(vv1);
// 			Vec3f vv2 = vv[v2-1]; pMatrix->Transform(vv2);
// //  		Vec3f vn0 = vn[n0-1]; pMatrix->TransformDirection(vn0);
// // 			Vec3f vn1 = vn[n1-1]; pMatrix->TransformDirection(vn1);
// //  		Vec3f vn2 = vn[n2-1]; pMatrix->TransformDirection(vn2);
// 			Vec3f vn0,vn1,vn2;
// 			Vec2f vt0 = vt[t0-1]; Vec2f vt1 = vt[t1-1]; Vec2f vt2 = vt[t2-1];
// 			TextureTriangle *pTriangle = new TextureTriangle(vv0,vv1,vv2,
// 				vt0,vt1,vt2,vn0,vn1,vn2,m_pCurrent_material);
// 			m_pKDTree->addTriangle(pTriangle);
// 		} // otherwise, must be whitespace
// 	}
// 	fclose(pFile);

void SceneParser::parseTriangle(Matrix *pMatrix) 
{
	char token[MAX_PARSER_TOKEN_LENGTH];
	// read in the sphere parameters
	getToken(token); assert (!strcmp(token, "{"));
	Vec3f v[3];	Vec3f vn[3]; Vec2f vt[3];
	int cv = 0, cvn = 0, cvt = 0;
	while ( getToken(token) )
	{
		if ( !strcmp(token, "v") )
			v[cv++] = readVec3f();
		else if ( !strcmp(token, "vn") )
			vn[cvn++] = readVec3f();
		else if ( !strcmp(token, "vt") )
			vt[cvt++] = readVec2f();
		else if( !strcmp(token, "}") )
			break;
		else {
			printf ("Unknown token in parseFile: '%s'\n", token);
			exit(0);
		}
	}
	assert( cv == 3 );
	if ( cvn == 0 && cvt == 0 ){
		Triangle *pTriangle =  new Triangle(v, m_pCurrent_material);
		m_pSceneTree->addTriangle(pTriangle);
	}
	else if( cvn == 3 && cvt == 0 ){
		Triangle *pTriangle =  new NormalTriangle(v, vn, m_pCurrent_material);
		m_pSceneTree->addTriangle(pTriangle);
	}
	else if( cvn ==3 && cvt == 3 ){
		Triangle *pTriangle =  new TextureTriangle(v, vn, vt, m_pCurrent_material);
		m_pSceneTree->addTriangle(pTriangle);
	}
	else if( cvn == 0 && cvt == 3 ){
		Triangle *pTriangle =  new TextureTriangle(v, vt, m_pCurrent_material);
		m_pSceneTree->addTriangle(pTriangle);
	}
}

void SceneParser::parseSphere()
{
	char token[MAX_PARSER_TOKEN_LENGTH];
	// read in the sphere parameters
	getToken(token); assert (!strcmp(token, "{"));
	getToken(token); assert (!strcmp(token, "center"));
	Vec3f center = readVec3f();
	getToken(token); assert (!strcmp(token, "radius"));
	float radius = readFloat();
	getToken(token); assert (!strcmp(token, "}"));
	Sphere *pSphere = new Sphere(center, radius, m_pCurrent_material);
	m_pSceneTree->addSphere(pSphere);
}

void SceneParser::parseTextureTriangle(Matrix *pMatrix)
{
	char token[MAX_PARSER_TOKEN_LENGTH];
	// read in the sphere parameters
	getToken(token); assert (!strcmp(token, "{"));
	getToken(token); assert (!strcmp(token, "v0"));
	Vec3f v0 = readVec3f(); pMatrix->Transform(v0);
	Vec3f n0 = readVec3f();	Vec2f t0 = readVec2f();
	getToken(token); assert (!strcmp(token, "v1"));
	Vec3f v1 = readVec3f(); pMatrix->Transform(v1);
	Vec3f n1 = readVec3f(); Vec2f t1 = readVec2f();
	getToken(token); assert (!strcmp(token, "v2"));
	Vec3f v2 = readVec3f(); pMatrix->Transform(v2);
	Vec3f n2 = readVec3f(); Vec2f t2 = readVec2f();
	getToken(token); assert (!strcmp(token, "}"));
	Triangle *pTriangle =  new TextureTriangle(v0,v1,v2, t0, t1, t2, n0, n1, n2, m_pCurrent_material);
	m_pSceneTree->addTriangle(pTriangle);
}

// ====================================================================
// ====================================================================
int SceneParser::getToken(char token[MAX_PARSER_TOKEN_LENGTH],FILE *pFile)
{
	if ( pFile==NULL )
		pFile = m_file;
	int success = fscanf(pFile,"%s ",token);
	if (success == EOF) {
		token[0] = '\0';
		return 0;}
	size_t len = strlen(token);
	if ( (len>=1 && token[0]=='#')||(len>=2 && token[0]=='/' && token[1]=='/') ){
		int suc = 1;
		while(suc!=EOF){
			char c;
			suc = fscanf(pFile, "%c", &c);
			if ( c == '\n' ) break;}
		return getToken(token,pFile);
	}
	if ( len>=2 && token[0]=='/' && token[1]=='*' ){
		while ( fscanf(pFile,"%s ",token) ){
			size_t len2 = strlen(token);
			if ( len2>=2 && token[len2-1]=='/' && token[len2-2]=='*' )
				break;
		}
		return getToken(token,pFile);
	}
	return 1;
}

Vec2f SceneParser::readVec2f(FILE *pFile)
{
	if ( pFile==NULL )
		pFile = m_file;
	float x,y;
	int count = fscanf(pFile,"%f %f",&x,&y);
	if (count != 2) {
		printf ("Error trying to read 3 floats to make a Vec3f\n");
		assert (0);
	}
	return Vec2f(x,y);
}

Vec3f SceneParser::readVec3f(FILE *pFile)
{
	if ( pFile==NULL )
		pFile = m_file;
	float x,y,z;
	int count = fscanf(pFile,"%f %f %f",&x,&y,&z);
	if (count != 3) {
		printf ("Error trying to read 3 floats to make a Vec3f\n");
		assert (0);
	}
	return Vec3f(x,y,z);
}

float SceneParser::readFloat(FILE *pFile) 
{
	if ( pFile==NULL )
		pFile = m_file;
	float answer;
	int count = fscanf(pFile,"%f",&answer);
	if (count != 1) {
		printf ("Error trying to read 1 float\n");
		assert (0);
	}
	return answer;
}

int SceneParser::readInt(FILE *pFile) 
{
	if ( pFile==NULL )
		pFile = m_file;
	int answer;
	int count = fscanf(pFile,"%d",&answer);
	if (count != 1) {
		printf ("Error trying to read 1 int\n");
		assert (0);
	}
	return answer;
}

void SceneParser::readString(char* str, FILE *pFile)
{
	if ( pFile == NULL )
		pFile = m_file;
	int count = fscanf(pFile, "%s", str);
	if (count != 1) {
		printf ("Error trying to read 1 string\n");
		assert (0);
	}
}

void SceneParser::debugMessage()
{
	m_pCamera->debugMessage();
	printf("background_color=");m_background_color.Write();printf("\n");
	printf("ambient_light=");m_ambient_light.Write();printf("\n");
	m_pSceneTree->debugMessage();
}